梦想不会自己发光,真正闪耀的是那个为梦狂奔的你。献给知行的孩子们!(Eric.He著)
本教程将从 C++ 匿名函数(lambda表达式)的核心概念、语法结构、使用规则到典型应用场景,全面拆解 lambda 表达式的核心用法,帮助你掌握这一现代 C++ 中高效且灵活的编程工具。
C++11 引入的lambda表达式(也称为匿名函数)是一种无需命名的内联函数,它允许在代码中直接定义短小的函数片段,可捕获上下文中的变量,是现代 C++ 中实现“函数式编程”和简化代码的核心特性。
lambda表达式本质是一个闭包(Closure)——能捕获并访问其所在作用域中变量的函数对象,编译器会自动将lambda表达式转换为一个匿名的类(仿函数),该类重载了 operator() 运算符。
| 特性 | 说明 |
|---|---|
| 匿名性 | 无需定义函数名,可直接在使用处内联定义,减少命名冗余 |
| 捕获性 | 可捕获所在作用域的变量(值捕获、引用捕获、混合捕获等) |
| 内联性 | 编译器可直接内联优化,性能优于普通函数调用 |
| 灵活性 | 支持参数、返回值、可变捕获,可作为参数传递给STL算法 |
| 临时性 | 通常用于临时的、短小的函数逻辑,用完即弃,无需复用 |
相比传统的函数/函数指针/仿函数,lambda表达式具有以下核心优势:
lambda表达式的完整语法格式如下(部分可选):
// 完整语法
[capture-list] (parameter-list) mutable noexcept -> return-type {
// 函数体(lambda的执行逻辑)
}
// 简化形式(常用)
[capture-list] (parameter-list) { 函数体 } // 无返回值/返回值自动推导
[capture-list] { 函数体 } // 无参数、无返回值
各部分说明:
[capture-list]:捕获列表(必须),指定捕获的变量及方式(parameter-list):参数列表(可选),与普通函数参数一致mutable:可变修饰符(可选),允许修改值捕获的变量noexcept:异常说明(可选),声明lambda不抛出异常-> return-type:返回值类型(可选),可省略,编译器自动推导{ 函数体 }:执行逻辑(必须),与普通函数体一致
#include
using namespace std;
int main() {
// 无捕获、无参数、无返回值的lambda
auto printHello = []() {
cout << "Hello, Lambda!" << endl;
};
// 调用lambda表达式(类似函数调用)
printHello();
// 直接调用(匿名使用,无需赋值给变量)
[]() {
cout << "匿名调用Lambda!" << endl;
}();
return 0;
}
输出结果:
Hello, Lambda!
匿名调用Lambda!
捕获列表用于指定lambda表达式可访问的外部变量,核心捕获方式如下:
| 捕获方式 | 语法 | 说明 |
|---|---|---|
| 空捕获 | [] |
不捕获任何外部变量 |
| 值捕获 | [var] / [=] |
[var]:捕获变量var(值传递);[=]:捕获所有外部变量(值传递) |
| 引用捕获 | [&var] / [&] |
[&var]:捕获变量var(引用传递);[&]:捕获所有外部变量(引用传递) |
| 混合捕获 | [=, &var] / [&, var] |
部分变量值捕获,部分变量引用捕获 |
| this捕获(类中) | [this] |
捕获当前类的this指针,可访问类的成员变量/函数 |
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 20;
// 1. 值捕获:捕获a(值传递),lambda内修改不影响外部
auto lambda1 = [a]() mutable {
a += 5; // 需加mutable才能修改值捕获的变量
cout << "lambda1内a = " << a << endl; // 输出:15
};
lambda1();
cout << "外部a = " << a << endl; // 输出:10(值捕获不影响外部)
// 2. 引用捕获:捕获b(引用传递),lambda内修改影响外部
auto lambda2 = [&b]() {
b += 5;
cout << "lambda2内b = " << b << endl; // 输出:25
};
lambda2();
cout << "外部b = " << b << endl; // 输出:25(引用捕获影响外部)
// 3. 混合捕获:a值捕获,b引用捕获
auto lambda3 = [a, &b]() mutable {
a += 10;
b += 10;
cout << "lambda3内a = " << a << ", b = " << b << endl; // 20, 35
};
lambda3();
cout << "外部a = " << a << ", b = " << b << endl; // 10, 35
// 4. 捕获所有变量:[=]值捕获所有,[&]引用捕获所有
auto lambda4 = [=]() {
cout << "lambda4内a = " << a << ", b = " << b << endl; // 10, 35
};
auto lambda5 = [&]() {
a += 5;
b += 5;
cout << "lambda5内a = " << a << ", b = " << b << endl; // 15, 40
};
lambda4();
lambda5();
cout << "外部a = " << a << ", b = " << b << endl; // 15, 40
return 0;
}
lambda表达式的返回值类型可省略,编译器会自动推导;若函数体包含多个return语句且类型不同,需显式指定返回值类型:
#include <iostream>
using namespace std;
int main() {
// 自动推导返回值(int)
auto add = [](int x, int y) {
return x + y;
};
cout << "3 + 5 = " << add(3, 5) << endl; // 输出:8
// 显式指定返回值类型(解决多return类型不一致问题)
auto calculate = [](int x, int y) -> double {
if (y != 0) {
return (double)x / y; // double类型
} else {
return 0; // int类型,需显式指定返回值为double
}
};
cout << "10 / 3 = " << calculate(10, 3) << endl; // 输出:3.33333
return 0;
}
C++14 支持通用lambda,使用auto作为参数类型,实现类似模板的效果:
#include <iostream>
#include <string>
using namespace std;
int main() {
// 通用lambda:参数类型自动推导
auto printAny = [](auto val) {
cout << "值:" << val << endl;
};
printAny(100); // 输出:值:100
printAny(3.14); // 输出:值:3.14
printAny("Hello Lambda"); // 输出:值:Hello Lambda
printAny(string("C++14")); // 输出:值:C++14
// 带默认参数的lambda(C++14)
auto addWithDefault = [](int x, int y = 10) {
return x + y;
};
cout << "5 + 默认值 = " << addWithDefault(5) << endl; // 输出:15
cout << "5 + 8 = " << addWithDefault(5, 8) << endl; // 输出:13
return 0;
}
值捕获的变量默认是const的,无法修改;添加mutable关键字后,允许在lambda内部修改值捕获的变量(仅影响内部副本,不影响外部):
#include <iostream>
using namespace std;
int main() {
int num = 10;
// 错误:值捕获的num默认const,无法修改
// auto lambdaErr = [num]() {
// num += 5; // 编译报错
// };
// 正确:加mutable允许修改内部副本
auto lambdaMutable = [num]() mutable {
num += 5;
cout << "lambda内num = " << num << endl; // 输出:15
};
lambdaMutable();
cout << "外部num = " << num << endl; // 输出:10(内部修改不影响外部)
return 0;
}
lambda表达式的本质是编译器自动生成的匿名仿函数类,lambda的调用等价于调用该类的operator()方法:
#include <iostream>
using namespace std;
// lambda表达式等价的仿函数实现
class LambdaEquivalent {
private:
int a; // 对应值捕获的变量
int& b; // 对应引用捕获的变量
public:
// 构造函数:接收捕获的变量
LambdaEquivalent(int a_, int& b_) : a(a_), b(b_) {}
// 重载operator()(mutable对应函数非const)
void operator()() mutable {
a += 5;
b += 5;
cout << "仿函数内a = " << a << ", b = " << b << endl;
}
};
int main() {
int a = 10, b = 20;
// lambda表达式
auto lambda = [a, &b]() mutable {
a += 5;
b += 5;
cout << "lambda内a = " << a << ", b = " << b << endl;
};
lambda(); // 输出:lambda内a = 15, b = 25
// 等价的仿函数调用
LambdaEquivalent func(a, b);
func(); // 输出:仿函数内a = 15, b = 30
return 0;
}
lambda可作为函数参数(需配合std::function)或返回值,实现灵活的回调函数:
#include <iostream>
#include <functional> // 包含std::function
using namespace std;
// 1. lambda作为函数参数(使用std::function)
void processData(int data, function<int(int)> handler) {
int result = handler(data);
cout << "处理后结果:" << result << endl;
}
// 2. lambda作为返回值
function<int(int)> getMultiplier(int factor) {
// 返回捕获factor的lambda
return [factor](int x) {
return x * factor;
};
}
int main() {
// 传递lambda作为参数
processData(10, [](int x) {
return x * 2; // 处理逻辑:乘以2
}); // 输出:处理后结果:20
// 获取返回的lambda
auto multiplyBy3 = getMultiplier(3);
cout << "5 * 3 = " << multiplyBy3(5) << endl; // 输出:15
auto multiplyBy5 = getMultiplier(5);
cout << "5 * 5 = " << multiplyBy5(5) << endl; // 输出:25
return 0;
}
lambda是STL算法的最佳搭档,可简化排序、遍历、查找等操作:
#include <iostream>
#include <vector>
#include <algorithm> // 包含STL算法
using namespace std;
int main() {
vector<int> nums = {5, 2, 9, 1, 5, 6};
// 1. 排序:按降序排列(替代自定义比较函数)
sort(nums.begin(), nums.end(), [](int a, int b) {
return a > b;
});
cout << "降序排序结果:";
for (int num : nums) cout << num << " "; // 输出:9 6 5 5 2 1
cout << endl;
// 2. 遍历:打印所有元素(替代for循环)
cout << "遍历容器:";
for_each(nums.begin(), nums.end(), [](int num) {
cout << num << " ";
}); // 输出:9 6 5 5 2 1
cout << endl;
// 3. 查找:查找第一个大于5的元素
auto it = find_if(nums.begin(), nums.end(), [](int num) {
return num > 5;
});
if (it != nums.end()) {
cout << "第一个大于5的元素:" << *it << endl; // 输出:9
}
// 4. 计数:统计等于5的元素个数
int count5 = count_if(nums.begin(), nums.end(), [](int num) {
return num == 5;
});
cout << "等于5的元素个数:" << count5 << endl; // 输出:2
return 0;
}
本教程从lambda表达式的核心概念、语法结构、进阶特性到典型应用场景,全面拆解了C++匿名函数的使用方法。掌握lambda表达式,能显著提升现代C++编程的效率和代码质量,是C++进阶学习的重要知识点。